﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace AgLux
{
    /// <summary>
    /// Represents a component that displays a picture.
    /// </summary>

    public class Picture : Component
    {
        protected Image _picture;
        protected Canvas _panelArea, _picturePanel;
        protected ScaleTransform _picturePanelScale;
        protected Canvas _enterPictureFullScreen, _leavePictureFullScreen;

        protected Storyboard _second, _picturePanelScaleUp, _picturePanelScaleDown;
        protected SplineDoubleKeyFrame _picturePanelScaleUpX, _picturePanelScaleUpY, _picturePanelScaleDownX, _picturePanelScaleDownY;

        protected double _filling;
        protected bool _isShowingPanel, _isFocusingPanel;

        /// <summary>
        /// Initializes a new instance of the Picture class.
        /// </summary>

        /// <param name="source">
        /// The source of the picture.
        /// </param>

        /// <param name="caption">
        /// The caption of the picture.
        /// </param>

        /// <param name="filling">
        /// The picture width as a percentage of the parent canvas width.
        /// </param>

        public Picture(string source, string caption, Filling filling)
            : base()
        {
            _picture = (Image)_resource.FindName("picture");
            _panelArea = (Canvas)_resource.FindName("panelArea");
            _picturePanel = (Canvas)_resource.FindName("picturePanel");
            _picturePanelScale = (ScaleTransform)_resource.FindName("picturePanelScale");

            _enterPictureFullScreen = (Canvas)_resource.FindName("enterPictureFullScreen");
            _leavePictureFullScreen = (Canvas)_resource.FindName("leavePictureFullScreen");

            _second = (Storyboard)_resource.FindName("second");
            _picturePanelScaleUp = (Storyboard)_resource.FindName("picturePanelScaleUp");
            _picturePanelScaleDown = (Storyboard)_resource.FindName("picturePanelScaleDown");

            _picturePanelScaleUpX = (SplineDoubleKeyFrame)_resource.FindName("picturePanelScaleUpX");
            _picturePanelScaleUpY = (SplineDoubleKeyFrame)_resource.FindName("picturePanelScaleUpY");
            _picturePanelScaleDownX = (SplineDoubleKeyFrame)_resource.FindName("picturePanelScaleDownX");
            _picturePanelScaleDownY = (SplineDoubleKeyFrame)_resource.FindName("picturePanelScaleDownY");

            _filling = (double)filling / 100;
            _isShowingPanel = _isFocusingPanel = false;

            _screen.Background = new SolidColorBrush(Colors.Black);
            _screen.MouseMove += new MouseEventHandler(ShowPanel);
            _enterPictureFullScreen.MouseLeftButtonDown += new MouseEventHandler(EnterFullScreen);
            _leavePictureFullScreen.MouseLeftButtonDown += new MouseEventHandler(LeaveFullScreen);

            _picture.Source = new Uri(source, UriKind.RelativeOrAbsolute);
            _panelArea.MouseEnter += new MouseEventHandler(FocusPanel);
            _panelArea.MouseLeave += new EventHandler(UnfocusPanel);

            _second.Completed += new EventHandler(CheckPanel);
            _picturePanelScaleUp.Completed += new EventHandler(TimePanel);
            _picturePanelScaleDown.Completed += new EventHandler(HidePanel);
            _caption.Text = caption;
        }

        /// <summary>
        /// Gets the picture content as HTML.
        /// </summary>

        public string Html
        {
            get
            {
                string html = "<img src=\"" + _picture.Source + "\"></img>";
                if (_caption.Text != null)
                {
                    html += "<br/><i><font style=\"font-family:Arial; font-size:10px;\">" + _caption.Text + "</font></i>";
                }

                return html;
            }
        }

        /// <summary>
        /// Prepare to display the component.
        /// </summary>

        /// <param name="width">
        /// The width of the canvas on which the component will be displayed.
        /// </param>

        public override void Prepare(double width)
        {
            base.Prepare(width);
            _screen.Width = _picture.Width = width * _filling;
            _panelArea.Width = _picturePanel.Width / 2;

            _panelArea.Height = _picturePanel.Height / 2;
            _panelArea.SetValue(Canvas.LeftProperty, _screen.Width / 2 - _panelArea.Width / 2);
            _picturePanel.SetValue(Canvas.LeftProperty, _panelArea.Width / 2 - _picturePanel.Width / 2);
            _picturePanel.SetValue(Canvas.TopProperty, _panelArea.Height / 2 - _picturePanel.Height / 2);
        }

        /// <summary>
        /// Ends the activity of the component.
        /// </summary>

        public override void End()
        {
            base.End();
            _second.Stop();
            _picturePanelScaleUp.Stop();
            _picturePanelScaleDown.Stop();

            _picturePanelScale.ScaleX = _picturePanelScale.ScaleY = 0;
            _isShowingPanel = _isFocusingPanel = false;
        }

        /// <summary>
        /// Occurs when it is time to start the activity of the component.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The EventArgs that contains the event data.
        /// </param>

        protected override void Start(object sender, EventArgs args)
        {
            base.Start(sender, args);
            _screen.Height = _picture.Height;
            SetCaption(_screen.Width);
            Height = _picture.Height + _caption.Height + 5;

            _panelArea.SetValue(Canvas.TopProperty, _screen.Height / 2 - _panelArea.Height / 2);
            _caption.SetValue(Canvas.TopProperty, Height - _caption.Height);
        }

        /// <summary>
        /// Occurs when it is time to enter full screen.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The MouseEventArgs that contains the event data.
        /// </param>

        protected override void EnterFullScreen(object sender, MouseEventArgs args)
        {
            base.EnterFullScreen(sender, args);
            double proportion = _picture.Width / _picture.Height;
            _screen.Width = _picture.Width = BrowserHost.ActualWidth;
            _screen.Height = BrowserHost.ActualHeight;

            if (_screen.Height < _screen.Width / proportion)
            {
                _picture.Width = _screen.Height * proportion;
                _picture.SetValue(Canvas.LeftProperty, (_screen.Width - _picture.Width) / 2);
            }
            else
            {
                _picture.SetValue(Canvas.TopProperty, (_screen.Height - _screen.Width / proportion) / 2);
            }

            _panelArea.Width = _picturePanel.Width;
            _panelArea.Height = _picturePanel.Height;
            _panelArea.SetValue(Canvas.LeftProperty, _screen.Width / 2 - _panelArea.Width / 2);
            _panelArea.SetValue(Canvas.TopProperty, _screen.Height / 2 - _panelArea.Height / 2);

            _picturePanel.SetValue(Canvas.LeftProperty, 0);
            _picturePanel.SetValue(Canvas.TopProperty, 0);
            _picturePanelScaleUpX.Value = _picturePanelScaleUpY.Value = _picturePanelScaleDownX.Value = _picturePanelScaleDownY.Value = 1;
            
            _caption.Visibility = Visibility.Collapsed;
            _enterPictureFullScreen.Visibility = Visibility.Collapsed;
            _leavePictureFullScreen.Visibility = Visibility.Visible;

            _second.Stop();
            _picturePanelScaleUp.Stop();
            _picturePanelScaleDown.Stop();

            _picturePanelScale.ScaleX = _picturePanelScale.ScaleY = 1;
            _isShowingPanel = true;
            _isFocusingPanel = false;
        }

        /// <summary>
        /// Occurs when it is time to leave full screen.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The MouseEventArgs that contains the event data.
        /// </param>

        protected override void LeaveFullScreen(object sender, MouseEventArgs args)
        {
            base.LeaveFullScreen(sender, args);
            double proportion = _picture.Height / _picture.Width;
            Prepare(Width);
            _screen.Height = _picture.Width * proportion;

            _picture.SetValue(Canvas.LeftProperty, 0);
            _picture.SetValue(Canvas.TopProperty, 0);
            _panelArea.SetValue(Canvas.TopProperty, _screen.Height / 2 - _panelArea.Height / 2);
            _picturePanelScaleUpX.Value = _picturePanelScaleUpY.Value = _picturePanelScaleDownX.Value = _picturePanelScaleDownY.Value = 0.5;

            _leavePictureFullScreen.Visibility = Visibility.Collapsed;
            _enterPictureFullScreen.Visibility = Visibility.Visible;
            _caption.Visibility = Visibility.Visible;

            _second.Stop();
            _picturePanelScaleUp.Stop();
            _picturePanelScaleDown.Stop();

            _picturePanelScale.ScaleX = _picturePanelScale.ScaleY = 0;
            _isShowingPanel = _isFocusingPanel = false;
        }

        /// <summary>
        /// Occurs when it is time to show the control panel.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The MouseEventArgs that contains the event data.
        /// </param>

        protected virtual void ShowPanel(object sender, MouseEventArgs args)
        {
            if (_isShowingPanel)
            {
                _second.Begin();
            }
            else if (Height > 0)
            {
                _isShowingPanel = true;
                _picturePanelScaleUp.Begin();
            }
        }

        /// <summary>
        /// Occurs when it is time to focus the control panel.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The MouseEventArgs that contains the event data.
        /// </param>

        protected virtual void FocusPanel(object sender, MouseEventArgs args)
        {
            _isFocusingPanel = true;
        }

        /// <summary>
        /// Occurs when it is time to unfocus the control panel.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The EventArgs that contains the event data.
        /// </param>

        protected virtual void UnfocusPanel(object sender, EventArgs args)
        {
            _isFocusingPanel = false;
        }

        /// <summary>
        /// Occurs when it is time to check if the control panel should be hidden.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The EventArgs that contains the event data.
        /// </param>

        protected virtual void CheckPanel(object sender, EventArgs args)
        {
            if (_isShowingPanel && !_isFocusingPanel)
            {
                _picturePanelScaleDown.Begin();
            }
        }

        /// <summary>
        /// Occurs to time the visibility of the control panel.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The EventArgs that contains the event data.
        /// </param>

        protected virtual void TimePanel(object sender, EventArgs args)
        {
            _second.Begin();
        }

        /// <summary>
        /// Occurs when it is time to hide the control panel.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The EventArgs that contains the event data.
        /// </param>

        protected virtual void HidePanel(object sender, EventArgs args)
        {
            _isShowingPanel = false;
        }
    }
}
